Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | import { and, eq } from 'drizzle-orm' import { NextResponse } from 'next/server' import { db, schema } from '@/db' import { withAuth } from '@/lib/auth/withAuth' import { getUserId } from '@/lib/viewer' import { normalizeBirthdayInput } from '@/lib/playerAge' /** * Check if a user can manage a player (owner or linked parent). */ async function canManagePlayer(playerId: string, userId: string): Promise<boolean> { // Check direct ownership const player = await db.query.players.findFirst({ where: and(eq(schema.players.id, playerId), eq(schema.players.userId, userId)), columns: { id: true }, }) if (player) return true // Check parent-child link const link = await db.query.parentChild.findFirst({ where: and( eq(schema.parentChild.childPlayerId, playerId), eq(schema.parentChild.parentUserId, userId) ), columns: { childPlayerId: true }, }) return !!link } /** * PATCH /api/players/[id] * Update a player (owner or linked parent) */ export const PATCH = withAuth(async (request, { params }) => { try { const { id } = (await params) as { id: string } const userId = await getUserId() const body = await request.json() let normalizedBirthday: string | null | undefined if (body.birthday === null) { normalizedBirthday = null } else if (typeof body.birthday === 'string') { normalizedBirthday = normalizeBirthdayInput(body.birthday) if (normalizedBirthday === null) { return NextResponse.json({ error: 'Invalid birthday' }, { status: 400 }) } } // Check authorization: owner or linked parent const authorized = await canManagePlayer(id, userId) if (!authorized) { return NextResponse.json({ error: 'Player not found or unauthorized' }, { status: 404 }) } // Security: Only allow updating specific fields (excludes userId) const [updatedPlayer] = await db .update(schema.players) .set({ ...(body.name !== undefined && { name: body.name }), ...(body.emoji !== undefined && { emoji: body.emoji }), ...(body.color !== undefined && { color: body.color }), ...(body.isActive !== undefined && { isActive: body.isActive }), ...(body.isArchived !== undefined && { isArchived: body.isArchived }), ...(body.notes !== undefined && { notes: body.notes }), ...(normalizedBirthday !== undefined && { birthday: normalizedBirthday }), }) .where(eq(schema.players.id, id)) .returning() if (!updatedPlayer) { return NextResponse.json({ error: 'Player not found' }, { status: 404 }) } return NextResponse.json({ player: updatedPlayer }) } catch (error) { console.error('Failed to update player:', error) return NextResponse.json({ error: 'Failed to update player' }, { status: 500 }) } }) /** * DELETE /api/players/[id] * Delete a player (owner or linked parent) */ export const DELETE = withAuth(async (_request, { params }) => { try { const { id } = (await params) as { id: string } const userId = await getUserId() const authorized = await canManagePlayer(id, userId) if (!authorized) { return NextResponse.json({ error: 'Player not found or unauthorized' }, { status: 404 }) } const [deletedPlayer] = await db .delete(schema.players) .where(eq(schema.players.id, id)) .returning() if (!deletedPlayer) { return NextResponse.json({ error: 'Player not found' }, { status: 404 }) } return NextResponse.json({ success: true, player: deletedPlayer }) } catch (error) { console.error('Failed to delete player:', error) return NextResponse.json({ error: 'Failed to delete player' }, { status: 500 }) } }) |